<script lang="ts" setup>
import { computed } from 'vue'

interface PasswordStrengthProps {
  modelValue: string
  placeholder?: string
  msg?: string
}

const props = withDefaults(defineProps<PasswordStrengthProps>(), {
  placeholder: '请输入',
  msg: '使用8个及以上的大小写字母、数字和符号',
})

const emit = defineEmits(['update:modelValue', 'change', 'input'])

// Password strength levels
enum PasswordStrengthLevel {
  None = 0,
  Weak = 1,
  Medium = 2,
  Strong = 3,
  VeryStrong = 4,
}

// Special characters regex pattern
const SPECIAL_CHARS_REGEX =
  /[`~!@#$^&*()=|{}':;',$$$$.<>/?~！@#￥……&*（）——|{}【】‘；：”“'。，、？]/

const checkPasswordStrength = (password: string): PasswordStrengthLevel => {
  if (!password || password.length < 8) {
    return PasswordStrengthLevel.None
  }

  let strength = PasswordStrengthLevel.None

  // Check for numbers
  if (/[0-9]/.test(password)) {
    strength++
  }

  // Check for lowercase letters
  if (/[a-z]/.test(password)) {
    strength++
  }

  // Check for uppercase letters
  if (/[A-Z]/.test(password)) {
    strength++
  }

  // Check for special characters
  if (SPECIAL_CHARS_REGEX.test(password)) {
    strength++
  }

  return strength
}

const passwordStrength = computed(() => checkPasswordStrength(props.modelValue))

const grade = computed(() => {
  const strength = passwordStrength.value
  return {
    lvl1: strength >= PasswordStrengthLevel.Weak ? 100 : 0,
    lvl2: strength >= PasswordStrengthLevel.Medium ? 100 : 0,
    lvl3: strength >= PasswordStrengthLevel.Strong ? 100 : 0,
    lvl4: strength >= PasswordStrengthLevel.VeryStrong ? 100 : 0,
  }
})
</script>

<template>
  <div class="password-strength-container">
    <div class="password-input-box">
      <el-input
        :model-value="modelValue"
        type="password"
        autocomplete="off"
        show-password
        show-word-limit
        :placeholder="placeholder"
        @update:modelValue="(value: string) => emit('update:modelValue', value)"
        @change="(value: string) => emit('change', value)"
        @input="(value: string) => emit('input', value)"
      />
    </div>

    <div class="strength-meter mt-2">
      <el-row :gutter="20">
        <el-col :span="6">
          <el-progress
            :text-inside="true"
            :stroke-width="10"
            :percentage="grade.lvl1"
            status="exception"
            :show-text="false"
            color="#F56C6C"
          />
        </el-col>
        <el-col :span="6">
          <el-progress
            :text-inside="true"
            :stroke-width="10"
            :percentage="grade.lvl2"
            status="exception"
            :show-text="false"
            color="#E6A23C"
          />
        </el-col>
        <el-col :span="6">
          <el-progress
            :text-inside="true"
            :stroke-width="10"
            :percentage="grade.lvl3"
            status="exception"
            :show-text="false"
            color="#909399"
          />
        </el-col>
        <el-col :span="6">
          <el-progress
            :text-inside="true"
            :stroke-width="10"
            :percentage="grade.lvl4"
            status="exception"
            :show-text="false"
            color="#67C23A"
          />
        </el-col>
      </el-row>
    </div>

    <div class="password-hint">
      <span>{{ msg }}</span>
    </div>
  </div>
</template>

<style scoped>
.password-strength-container {
  width: 100%;
}

.strength-meter {
  margin-top: 0.5rem;
}

.password-hint {
  margin-top: 10px;
  line-height: 20px;
  color: #c0c4cc;
}
</style>
